/*
 * bsp_timer.c
 *
 *  Created on: 2023年6月28日
 *      Author: mcealt_DS
 */

#include "bsp_timer.h"
#include "app_log.h"
#include "app_led.h"

#if defined(SM_SOUND)
static ds_gpio_t alarmLed = {
      .port = gpioPortC,
      .pin = 1,
      .mode = gpioModePushPull,
      .initial = 0,
      .valid = 1,
};
#endif

#if defined(SM_OUTSOUND)
static ds_gpio_t alarmLed[3] = {
    {
        .port = gpioPortC,        //右1
        .pin = 5,
        .mode = gpioModePushPull,
        .initial = 0,
        .valid = 1,
    },
    {
        .port = gpioPortC,        //中
        .pin = 3,
        .mode = gpioModePushPull,
        .initial = 0,
        .valid = 1,
    },
    {
        .port = gpioPortC,        //左1
        .pin = 2,
        .mode = gpioModePushPull,
        .initial = 0,
        .valid = 1,
    }

};
#endif

void pwm_init(void)
{
  TIMER_Init_TypeDef sTimerInit = TIMER_INIT_DEFAULT;
  TIMER_InitCC_TypeDef sInitCC = TIMER_INITCC_DEFAULT;

  CMU_ClockEnable(PWM_TIMER_CLOCK, true);
  CMU_ClockSelectSet(PWM_TIMER_CLOCK, cmuSelect_HFXO); /* ULFRCO as clock source */

  sTimerInit.enable = false; //初始化时不开启定时器
  TIMER_Init(PWM_TIMER, &sTimerInit);

  CMU_ClockEnable(cmuClock_GPIO, true);
  GPIO_PinModeSet(BEEP_PWM_PORT, BEEP_PWM_PIN, gpioModePushPull, 0);

  sInitCC.mode = timerCCModePWM;
  sInitCC.cmoa = timerOutputActionToggle;
  sInitCC.edge = timerEdgeBoth;
  sInitCC.outInvert = 0;
  TIMER_InitCC(PWM_TIMER, BEEP_PWM_CHANNEL, &sInitCC);
#if defined(SM_SOUND) || defined(SM_OUTSOUND)
  GPIO->TIMERROUTE[TIMER_NUM(PWM_TIMER)].ROUTEEN = GPIO_TIMER_ROUTEEN_CC0PEN;
  GPIO->TIMERROUTE[TIMER_NUM(PWM_TIMER)].CC0ROUTE =
    (BEEP_PWM_PORT << _GPIO_TIMER_CC0ROUTE_PORT_SHIFT)
    | (BEEP_PWM_PIN << _GPIO_TIMER_CC0ROUTE_PIN_SHIFT);
#if defined(SM_SOUND)
  ds_gpio_init(&alarmLed);
#else
  ds_gpio_init(&alarmLed[0]);
  ds_gpio_init(&alarmLed[1]);
  ds_gpio_init(&alarmLed[2]);
#endif
#else
  GPIO->TIMERROUTE[TIMER_NUM(PWM_TIMER)].ROUTEEN = GPIO_TIMER_ROUTEEN_CC0PEN;
  GPIO->TIMERROUTE[TIMER_NUM(PWM_TIMER)].CC0ROUTE =
    (BEEP_PWM_PORT << _GPIO_TIMER_CC0ROUTE_PORT_SHIFT)
    | (BEEP_PWM_PIN << _GPIO_TIMER_CC0ROUTE_PIN_SHIFT);
#endif

  uint16_t timerTicks = (uint16_t)(CMU_ClockFreqGet(PWM_TIMER_CLOCK) / PWM_FREQUENCY_DEFAULT); //初始化无分频
  TIMER_TopSet(PWM_TIMER, timerTicks);
}

static uint8_t s_beepPwmDuty = 50;

static uint16_t s_presetFreq = 0;
static uint16_t s_timerTicks = 0;
static uint32_t s_beepCompareValue = 0;

void pwm_frequency_preset(uint16_t frequency)
{
  s_timerTicks = (uint16_t)(CMU_ClockFreqGet(PWM_TIMER_CLOCK) / frequency); // 新的topValue
  s_beepCompareValue = s_timerTicks * s_beepPwmDuty / 100;
  s_presetFreq = frequency;
}

void pwm_frequency_set(uint16_t frequency)
{
  if(s_presetFreq != frequency)
  {
     pwm_frequency_preset(frequency);
  }
  //TIMER_TopSet(PWM_TIMER, s_timerTicks);
  TIMER_TopBufSet(PWM_TIMER, s_timerTicks);
  TIMER_CompareBufSet(PWM_TIMER, BEEP_PWM_CHANNEL, s_beepCompareValue);
}
//仅设置PWM占空比的控制变量值
void pwm_duty_value_set(uint8_t duty)
{
  s_beepPwmDuty = duty;
}

void pwm_duty_set(uint8_t channel, uint8_t duty)
{
  uint32_t topValue = 0;
  if(channel == 0 ) {
      topValue = TIMER_TopGet(PWM_TIMER);
      s_beepCompareValue = topValue * duty / 100;
      TIMER_CompareBufSet(PWM_TIMER, BEEP_PWM_CHANNEL, s_beepCompareValue);
      s_beepPwmDuty = duty;
  }

#if defined(SM_SOUND) || defined(SM_OUTSOUND)
  else if(channel == 1 && false == ledStateGet()) {
      if(duty > 0) {
#if defined(SM_SOUND)
          ds_gpio_on(&alarmLed);
#else
          ds_gpio_on(&alarmLed[0]);
          ds_gpio_on(&alarmLed[1]);
          ds_gpio_on(&alarmLed[2]);
#endif
      }
      else {
#if defined(SM_SOUND)
          ds_gpio_off(&alarmLed);
#else
          ds_gpio_off(&alarmLed[0]);
          ds_gpio_off(&alarmLed[1]);
          ds_gpio_off(&alarmLed[2]);
#endif
      }
  }
#endif
}

//ToDo 中断内修改频率和占空比
void pwm_start()
{
  TIMER_Enable(PWM_TIMER, 1);
}

void pwm_stop()
{
  TIMER_Enable(PWM_TIMER, 0);
}

